
//***************************************************************************
//  Request
//***************************************************************************


/** @struct Request
 *
 *  @brief Collision detection request like "add" or "remove" an object/callback.
 *
 * This struct will be passed to col::request().
 *
 * @author Gabriel Zachmann
 *
 * @todo
 */


/** Create a "single object request"
 *
 * @param req			the request (ADD_OBJECT,ACTIVATE_OBJECT)
 * @param node			the node
 *
 * @warning
 *   The constructor does @e not check if @a nodeptr is already
 *   registered with the collision detection module.
 *
 * @throw XCollision
 *   If the node does not have a geometry or is NullPtr.
 * @throw XCollision
 *   If the type of request is not a single object request.
 *
 * @todo
 *   Can we make nodeptr const? That would be much nicer,
 *   because they must not change after the ctor.
 */


//---------------------------------------------------------------------------
//  Includes
//---------------------------------------------------------------------------


#include <stdlib.h>
#include <stdio.h>
#include <vector>

#include <boost/static_assert.hpp>

#define COL_EXPORT

#include <ColDefs.h>
#include <Collision.h>
#include <ColExceptions.h>
#include <ColQueue.h>
#include <ColObj.h>
#include <ColUtils.h>
#include <ColPipelineData.h>
#include <ColGrid.h>
#include <ColGridObj.h>
#include <ColRequest.h>


namespace col {

Request::Request( RequestE inreq, ColID inID )
:
	req(inreq),
	objID(inID)
{
	if ( req != ACTIVATE_OBJECT &&
		 req != DEACTIVATE_OBJECT )
		throw XCollision("Request called, but request is illegal");
}

Request::Request( RequestE inreq, ColID inID, const ColGeometry *ingeom )
:
	req(inreq),
	objID(inID),
	geom(ingeom)
{
	if ( req != ADD_OBJECT )
		throw XCollision("Request called, but request is illegal");
}

Request::Request( RequestE inreq, ColID inID, const Matrix4 *intran )
:
	req(inreq),
	objID(inID),
	tran(intran)
{
	if ( req != MOVE_OBJECT )
		throw XCollision("Request called, but request is illegal");
}


/** Create a "two objects request"
 *
 * @param inreq			the request (ADD_OBJECT,ACTIVATE_OBJECT)
 * @param incallback	a collision callback
 *
 * @pre
 *   @a callback should be valid.
 *
 * @warning
 *   The constructor does @e not check if the objects in @a callback have
 *   already been registered with the collision detection module.
 *
 * @throw XCollision
 *   If the type of request is not a two object request.
 * @throw XCollision
 *   If @a callback seems to be improperly constructed.
 *
 */
Request::Request( RequestE inreq, Callback *incallback )
:	
	req(inreq),
	callback(incallback)
{
	if ( req != ADD_CALLBACK &&
		 req != ADD_CYCLE_CALLBACK )
		throw XCollision("Request called, but request is illegal");

	if ( ! callback )
		throw XCollision("Request(callback): callback=NULL");

	if ( req == REMOVE_CALLBACK ||
		 req == ADD_CALLBACK )
		if ( (callback->obj1ID < 0) !=
			 (callback->obj2ID < 0)  )
			throw XCollision("Request(callback): obj1 / obj2 inconsistent"
							 " ==/!= Null");
}

void Request::operator = ( const Request &source )
{
	if ( this == &source )
		return;

	req			= source.req;
	objID		= source.objID;
	geom		= source.geom;
	tran		= source.tran;
	callback	= source.callback;
}



/** Process a request to the collision detection module
 *
 * @warning
 *   This function probably runs in a different thread than the constructor!
 *
 * @todo
 * - Some types not yet implementated.
 * - process()const machen, wenn OSG erlaubt
 * - @c show_hulls anders (z.B. als define) implementieren
 */
void Request::process( bool show_hulls,
					  AlgoE algo,
					  Matrix* collmatrix,
					  std::vector<ColObj*> *colobjs,
					  std::vector<Callback*> &cycle_callbacks,
					  bool useHulls,
					  Grid* grid)
{
#ifdef	_DEBUG
	printf("process: %s\n",
#ifdef _WIN32
		   const_cast<char*>( getName() ) );
#else
		   getName() );
#endif
#endif

	if ( req == ADD_OBJECT )
	{
	    ColObj * obj = new ColObj( objID, geom, false, false, useHulls, algo, grid, show_hulls );
        colobjs->push_back( obj );
		collmatrix->addObj( colobjs->back() );
		// cannot addObj( &obj ); memory leak
	}
	else
	if ( req == MOVE_OBJECT )
	{
		(*colobjs)[objID]->setTransMatrix( tran );
	}
	else
    if ( req == DEACTIVATE_OBJECT )
    {
		(*colobjs)[objID]->setActive( false );
    }
    else
    if ( req == ACTIVATE_OBJECT )
    {
		(*colobjs)[objID]->setActive( true );
    }

	else
	if ( req == ADD_CALLBACK )
	{
		collmatrix->addCallback( callback, colobjs );
	}
	else
	if ( req == ADD_CYCLE_CALLBACK )
	{
		cycle_callbacks.push_back( callback );
	}
	else
		fputs("Request::process: not yet implemented!\n",stderr);
}


const char *Request::Names[] =
{
	"ADD_OBJECT",
	"REMOVE_OBJECT",
	"ACTIVATE_OBJECT",
	"DEACTIVATE_OBJECT",
	"MOVE_OBJECT",
	"ADD_CALLBACK",
	"REMOVE_CALLBACK",
	"ADD_CYCLE_CALLBACK"
};


const char * Request::getName( void ) const
{
	return Request::Names[req];
}


} // namespace col
